using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.UI;

namespace Acms.AcmsControls
{
    public class RenderFile : System.Web.UI.Page
    {
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!IsPostBack)
            {
                int id = 0;
                int width = 0;
                int height = 0;
                bool ignoreCache = false;
                string path;
                string name;
                bool attachment = false;

                if (Request.QueryString["Id"] != null)
                {
                    try
                    {
                        id = int.Parse(Request.QueryString["Id"]);
                    }
                    catch
                    {
                    }
                }

                if (Request.QueryString["Width"] != null)
                {
                    try
                    {
                        width = int.Parse(Request.QueryString["Width"]);
                    }
                    catch
                    {
                    }
                }


                if (Request.QueryString["Height"] != null)
                {
                    try
                    {
                        height = int.Parse(Request.QueryString["Height"]);
                    }
                    catch
                    {
                    }
                }

                if (Request.QueryString["IgnoreCache"] != null)
                {
                    try
                    {
                        ignoreCache = bool.Parse(Request.QueryString["IgnoreCache"]);
                    }
                    catch
                    {
                    }
                }

                if (Request.QueryString["Attachment"] != null)
                {
                    try
                    {
                        attachment = bool.Parse(Request.QueryString["Attachment"]);
                    }
                    catch
                    {
                    }
                }

                path = Request.QueryString["Path"];
                name = Request.QueryString["Name"];

                if (id > 0)
                {
                    Acms.Bll.File file = null;
                    if (!ignoreCache)
                    {
                        file = Cache[string.Concat("AcmsFile_", id)] as Acms.Bll.File;
                    }
                    if (file == null)
                    {
                        file = Acms.Bll.File.GetById(id);
                        Cache.Add(string.Concat("AcmsFile_", id), file, null, DateTime.MaxValue, TimeSpan.FromMinutes(30), System.Web.Caching.CacheItemPriority.BelowNormal, null);
                    }
                    if (file != null)
                    {
                        if (file.LogDownload || !string.IsNullOrEmpty(path) || !string.IsNullOrEmpty(name))
                        {
                            Acms.Bll.User tmpUser = null;
                            if(Page.User != null && Page.User.Identity != null && Page.User.Identity is Acms.Bll.UserIdentity)
                            {
                                tmpUser = ((Acms.Bll.UserIdentity)Page.User.Identity).User;
                            }
                            Acms.Bll.FileDownload log = Acms.Bll.FileDownload.CreateInstance(file, tmpUser, System.Net.IPAddress.Parse(Request.UserHostAddress));
                            log.Path = path;
                            log.Name = name;
                            log.Update();
                        }
                        switch (file.FileType)
                        {
                            case Acms.Bll.File.FileTypes.Image:
                                if (width == 0 && height == 0)
                                {
                                    RenderFileData(file, attachment);
                                }
                                else
                                {
                                    RenderImage(file, width, height, attachment);
                                }
                                break;
                            default:
                                RenderFileData(file, attachment);
                                break;
                        }
                    }
                    else
                    {
                        RenderError();
                    }
                }
                else if (id <= -1)
                {
                    RenderDummyImage(id, width, height, attachment);
                }
                else
                {
                    RenderError();
                }
            }

        }

        private void RenderFileData(Acms.Bll.File file, bool attachment)
        {
            Response.Clear();
            Response.AppendHeader("Content-Disposition", string.Format("{0}filename=\"{1}{2}\"", attachment ? "attachment;" : "", file.Name, file.Extension));
            Response.ContentType = file.ContentType;
            Response.OutputStream.Write(file.FileData, 0, file.FileData.Length);
            Response.End();

        }

        private void RenderError()
        {
            Response.StatusCode = 404;
            Response.End();
        }

        private void RenderDummyImage(int index, int width, int height, bool attachment)
        {
            Bitmap tmp = null;
            switch (index)
            {
                case -1:
                    tmp = Properties.Resources.image1;
                    break;
                case -2:
                    tmp = Properties.Resources.image2;
                    break;
                case -3:
                    tmp = Properties.Resources.image3;
                    break;
                case -4:
                    tmp = Properties.Resources.image4;
                    break;
                case -5:
                    tmp = Properties.Resources.image5;
                    break;
                case -6:
                    tmp = Properties.Resources.image6;
                    break;
                case -7:
                    tmp = Properties.Resources.image7;
                    break;
                case -8:
                    tmp = Properties.Resources.image8;
                    break;

            }
            Bitmap resized = ResizeBitMap(tmp, width, height);
            Response.Clear();
            Response.AppendHeader("Content-Disposition", string.Format("{0}filename=\"Dummy_{1}{2}\"", attachment ? "attachment;" : "", index * -1, ".jpg"));
            RenderJpeg(resized);
        }

        private void RenderImage(Acms.Bll.File file, int width, int height, bool attachment)
        {

            Bitmap bitmap = ResizeBitMap(file, width, height);
            if (bitmap != null)
            {
                Response.Clear();
                Response.AppendHeader("Content-Disposition", string.Format("{0}filename=\"{1}{2}\"", attachment ? "attachment;" : "", file.Name, file.Extension));

                switch (file.ContentType)
                {
                    case "image/jpeg":
                    case "image/pjpeg":
                    case "image/jpg":
                        RenderJpeg(bitmap);
                        break;
                    case "image/gif":
                        RenderGif(bitmap);
                        break;
                    case "image/png":
                    case "image/x-png":
                        RenderPng(bitmap);
                        break;
                    default:
                        RenderError();
                        break;
                }
            }
            else
            {
                RenderError();
            }
        }

        private System.Drawing.Imaging.ImageCodecInfo GetJpecEncoder()
        {
            return System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[1];
        }

        private void RenderJpeg(Bitmap bitmap)
        {
            System.Drawing.Imaging.ImageCodecInfo encoder = GetJpecEncoder();
            Response.ContentType = encoder.MimeType;
            System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters(1);
            parameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L);
            bitmap.Save(Response.OutputStream, encoder, parameters);
            Response.End();
            bitmap.Dispose();
        }


        private System.Drawing.Imaging.ImageCodecInfo GetGifEncoder()
        {
            return System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[2];
        }
        
        private void RenderGif(Bitmap bitmap)
        {
            System.Drawing.Imaging.ImageCodecInfo encoder = GetGifEncoder();

            System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters(0);

            Acms.ImageManipulation.OctreeQuantizer quantizer = new Acms.ImageManipulation.OctreeQuantizer ( 128 , 8 ) ;
            Bitmap quantized = quantizer.Quantize ( bitmap );
            bitmap.Dispose();

            Response.ContentType = encoder.MimeType;
            
            quantized.Save ( Response.OutputStream, encoder, parameters) ;

            Response.End();
            quantized.Dispose();
        }

        private System.Drawing.Imaging.ImageCodecInfo GetPngEncoder()
        {
            return System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[4];
        }

        private void RenderPng(Bitmap bitmap)
        {

            System.Drawing.Imaging.ImageCodecInfo encoder = GetPngEncoder();

            System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters(0);

            System.IO.MemoryStream mem = new System.IO.MemoryStream();
            bitmap.Save(mem, encoder, parameters);

            Response.ContentType = encoder.MimeType;
            mem.WriteTo(Response.OutputStream);
            Response.End();
            
            bitmap.Dispose();
        }

        private Bitmap CreateBitmap(Acms.Bll.File file)
        {
            System.IO.MemoryStream mem = file.GetFileStream();

            if (mem != null)
            {
                Bitmap bitmap = new Bitmap(mem);
                return bitmap;
            }
            else
            {
                return null;
            }
        }

        private decimal GetResizeFactor(int targetWidth, int targetHeight, int imageWidth, int imageHeight)
        {
            decimal factor = 1;
            if (targetWidth != 0 && targetHeight != 0 && (imageWidth > targetWidth || imageHeight > targetHeight))
            {
                decimal widthFactor = (decimal)targetWidth / (decimal)imageWidth;
                decimal heightFactor = (decimal)targetHeight / (decimal)imageHeight;

                if (widthFactor > heightFactor)
                {
                    factor = heightFactor;
                }
                else
                {
                    factor = widthFactor;
                }
            }
            else if (targetWidth != 0 && imageWidth > targetWidth)
            {
                factor = (decimal)targetWidth / (decimal)imageWidth;
            }
            else if (targetHeight != 0 && imageHeight > targetHeight)
            {
                factor = (decimal)targetHeight / (decimal)imageHeight;
            }
            return factor;
        }

        private Bitmap ResizeBitMap(Bitmap bitmap, int width, int height)
        {
            if (bitmap != null)
            {
                //get the fractor to shrink by
                decimal factor = GetResizeFactor(width, height, bitmap.Width, bitmap.Height);
                int actualWidth = (int)Math.Ceiling(Math.Round(bitmap.Width * factor, 1));
                int actualHeight = (int)Math.Ceiling(Math.Round(bitmap.Height * factor, 1));

                Bitmap resized = new Bitmap(actualWidth, actualHeight);
                Graphics g = Graphics.FromImage(resized);

                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode  = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                g.FillRectangle(Brushes.White, 0, 0, actualWidth, actualHeight);
                
                g.DrawImage(bitmap, 0, 0, actualWidth, actualHeight);
                g.Dispose();
                bitmap.Dispose();
                return resized;
            }
            else
            {
                return null;
            }
        }

        private Bitmap ResizeBitMap(Acms.Bll.File file, int width, int height)
        {
            Bitmap bitmap = CreateBitmap(file);
            if (bitmap != null)
            {
                return ResizeBitMap(bitmap, width, height);
            }
            else
            {
                return null;
            }
        }

        public static string GetUrl(int fileId, Page page)
        {
            string key = string.Concat("AcmsFileUrl_", fileId);
            string val = page.Cache[key] as string;
            if (string.IsNullOrEmpty(val))
            {
                var file = Bll.FileInfo.GetById(fileId);
                if (file != null)
                {
                    val = string.Format("~/AcmsFile/{0}/{1}{2}", file.Id, file.Name, file.Extension);
                }
                page.Cache.Add(key, val, null, DateTime.MaxValue, TimeSpan.FromHours(2), System.Web.Caching.CacheItemPriority.Normal, null);
            }
            return val;
        }

        public static string GetUrl(int fileId, int? width, int? height, Page page)
        {
            string key = string.Concat("AcmsFileUrl_", fileId, "_", width, "_", height);
            string val = page.Cache[key] as string;
            if (string.IsNullOrEmpty(val))
            {
                if (fileId > 0)
                {
                    var file = Bll.FileInfo.GetById(fileId);
                    if (file != null)
                    {
                        val = string.Format("~/AcmsFile/{0}/{1}/{2}/{3}{4}", file.Id, width ?? 0, height ?? 0, file.Name, file.Extension);
                    }
                }
                else
                {
                    //must be a dev file eg -1, -2 etc
                    val = string.Format("~/AcmsFile/{0}/{1}/{2}/{3}{4}", fileId, width ?? 0, height ?? 0, "File Name Here", "File Extension Here");
                }
                page.Cache.Add(key, val, null, DateTime.MaxValue, TimeSpan.FromHours(2), System.Web.Caching.CacheItemPriority.Normal, null);
            }
            return val;
        }
    }
}
